Optofidelity: Add frame verification to initialization step The VerifyFrame method checks if the camera shifted or the light setup changed. Both will cause a test run to be aborted and the camera calibration to be re-executed. BUG=chromium:395174 TEST=python self_tests.py -d Change-Id: I9c6567af6210432fad1baf82d60ecdc2ca446a2f Reviewed-on: https://chromium-review.googlesource.com/221491 Reviewed-by: Charles Mooney <charliemooney@chromium.org> Commit-Queue: Dennis Kempin <denniskempin@chromium.org> Tested-by: Dennis Kempin <denniskempin@chromium.org> 
diff --git a/optofidelity/optofidelity/detection/processor.py b/optofidelity/optofidelity/detection/processor.py index af16645..c1f244d 100644 --- a/optofidelity/optofidelity/detection/processor.py +++ b/optofidelity/optofidelity/detection/processor.py 
@@ -20,6 +20,12 @@  self.detectors[detector.name] = detector    def Initialize(self, video_reader, debug=[]): + # verify in the first frame that the test area is still valid + first_frame = video_reader.FrameAt(0) + self.test_area.VerifyFrame(first_frame, + "verification" in debug or "all" in debug) + + # initialize all detectors  video = Video(video_reader, self.test_area)  for detector in self.detectors.itervalues():  debug_flag = debug and (detector.name in debug or "all" in debug) 
diff --git a/optofidelity/optofidelity/detection/screen.py b/optofidelity/optofidelity/detection/screen.py index 16aeebd..1dce9cb 100644 --- a/optofidelity/optofidelity/detection/screen.py +++ b/optofidelity/optofidelity/detection/screen.py 
@@ -169,6 +169,51 @@  rectified_off=self.off_image)  return True   + def NormalizedBrightness(self, rectified_frame, slice_or_mask=None): + """Returns normalized average brightness of frame. + + The brightness is normalized to 0 being the average brightness of the + screen being black and 1 the average brightness of a fully white screen. + """ + if slice_or_mask is not None: + mean = np.mean(rectified_frame[slice_or_mask]) + on_mean = np.mean(self.on_image[slice_or_mask]) + off_mean = np.mean(self.off_image[slice_or_mask]) + else: + mean = np.mean(rectified_frame[:]) + on_mean = np.mean(self.on_image[:]) + off_mean = np.mean(self.off_image[:]) + return (mean - off_mean) / (on_mean - off_mean) + + def VerifyFrame(self, frame, debug=False): + """Check frame for camera shifts or lighting changes.""" + rectified = self.Rectify(frame) + width, height = rectified.shape + + # calculate overall mean and mean along screen edges + mean = self.NormalizedBrightness(rectified) + top_mean = self.NormalizedBrightness(rectified, np.s_[:, 0]) + left_mean = self.NormalizedBrightness(rectified, np.s_[0, :]) + bottom_mean = self.NormalizedBrightness(rectified, np.s_[:, height - 1]) + right_mean = self.NormalizedBrightness(rectified, np.s_[width - 1, :]) + edge_means = [top_mean, left_mean, bottom_mean, right_mean] + + if debug: + print "Overall mean:", mean + print "Edge means:", edge_means + + # The brightness is normalized to the black screen being 0 and the white + # screen being 1. If the lighting changed, the normalized brightness will + # be outside the [0, 1] range. + if mean > 1.1 or mean < -0.1: + raise VideoException("Lighting changed.") + + # If the bezel shifted into the screen the deviation of the edge means + # from the overall mean will be strong. + deviations = np.abs(edge_means - mean) + if np.any(deviations > 0.5): + raise VideoException("Camera shifted.") +    class ScreenFlash(Detector):  """Represents the device screen in the video stream.